
package com.jf.cloud.live.service.impl;

import cn.binarywang.wx.miniapp.bean.live.WxMaCreateRoomResult;
import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult;
import cn.binarywang.wx.miniapp.bean.live.WxMaLiveRoomInfo;
import cn.hutool.core.date.DateUtil;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.common.util.ImageUtil;
import com.jf.cloud.common.util.Json;
import com.jf.cloud.live.config.WxConfig;
import com.jf.cloud.live.constant.LiveConstant;
import com.jf.cloud.live.constant.LiveInterfaceType;
import com.jf.cloud.live.constant.WxErrorCode;
import com.jf.cloud.live.dto.LiveLogDTO;
import com.jf.cloud.live.dto.LiveRoomDTO;
import com.jf.cloud.live.mapper.LiveRoomMapper;
import com.jf.cloud.live.model.LiveLog;
import com.jf.cloud.live.model.LiveRoom;
import com.jf.cloud.live.service.LiveLogService;
import com.jf.cloud.live.service.LiveRoomService;
import com.jf.cloud.live.util.WxImageUtil;
import com.jf.cloud.live.vo.LiveRoomVO;
import ma.glasnost.orika.MapperFacade;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 直播间
 *
 * @author zz
 * @date 2022-08-17 17:09:06
 */
@Service
public class LiveRoomServiceImpl implements LiveRoomService {

    /**
     * 一页的数量
     */
    private static final Long MAX_PAGE_NUM = 80L;
    @Autowired
    private LiveRoomMapper liveRoomMapper;
    @Autowired
    private LiveLogService liveLogService;
    @Autowired
    private WxConfig wxConfig;

    private static final Logger log = LoggerFactory.getLogger(LiveRoomServiceImpl.class);
    @Autowired
    private WxImageUtil wxImageUtil;

    @Autowired
    private MapperFacade mapperFacade;

    @Value("${biz.oss.resources-url}")
    private String imgDomain;

    @Override
    public PageVO<LiveRoom> page(PageDTO pageDTO, LiveRoom liveRoom) {
        return PageUtil.doPage(pageDTO, () -> liveRoomMapper.list(liveRoom));
    }

    @Override
    public LiveRoom getById(Long id) {
        return liveRoomMapper.getById(id);
    }

    @Override
    public void save(LiveRoom liveRoom) {
        liveRoomMapper.save(liveRoom);
    }

    @Override
    public void update(LiveRoom liveRoom) {
        liveRoomMapper.update(liveRoom);
    }

    @Override
    public void deleteById(Long id) {
        liveRoomMapper.deleteById(id);
    }

    @Override
    public int countTopRoom() {
        return liveRoomMapper.countTopRoom();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeRoomById(Long id, Long shopId) {
        // 1.校验今日可用次数并保存or修改商家次数记录
        liveLogService.checkNumsAndSaveLog(shopId, LiveInterfaceType.REMOVE_LIVE_ROOM, "删除直播间");
        LiveRoom liveRoom = getById(id);
        if (!Objects.equals(shopId, liveRoom.getShopId()) && !Objects.equals(Constant.PLATFORM_SHOP_ID, shopId)) {
            // 没有权限进行操作！
            throw new LuckException("没有权限进行操作");
        }
        boolean isDelete = false;
        try {
            isDelete = wxConfig.getWxMaService().getLiveService().deleteRoom(liveRoom.getRoomId());
        } catch (WxErrorException e) {
            //微信直播控制台不存在该房间 (微信返回错误码：300022：此房间号不存在)，则不抛出异常，直接在数据库删除
            if (e.getError().getErrorCode() != WxErrorCode.LIVE_ROOM_IS_NOT_EXIST.value()) {
                // 删除直播间失败
                log.error("删除直播间失败！", liveRoom.getRoomId());
                log.error(e.getError().getErrorMsg());
                throw new LuckException("删除直播间失败！");
            }
        }
        deleteById(id);
        return isDelete;
    }

    /**
     * 定时每分钟去同步微信的直播间接口
     *
     * @throws WxErrorException 微信异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void synchronousWxLiveRoom() {
        // 首先校验商家今日可用次数
        LiveLogDTO liveLogDTO = new LiveLogDTO();
        liveLogDTO.setShopId(Constant.PLATFORM_SHOP_ID);
        liveLogDTO.setStartTime(DateUtil.beginOfDay(new Date()));
        liveLogDTO.setEndTime(DateUtil.endOfDay(new Date()));
        liveLogDTO.setType(LiveInterfaceType.ROOM_LIST.value());
        LiveLog liveLogDb = liveLogService.getLiveLogByParams(liveLogDTO);
//         如果次数大于上限则取消继续
        if (Objects.nonNull(liveLogDb) && liveLogDb.getNum() > LiveInterfaceType.ROOM_LIST.getNumLimit()) {
            log.info("平台今日可用获取直播间信息的次数已达上限！");
            return;
        }

        List<WxMaLiveResult.RoomInfo> liveInfos;
        try {
            liveInfos = wxConfig.getWxMaService().getLiveService().getLiveInfos();
        } catch (Exception e) {
            log.error("同步直播间信息失败！");
            log.error(e.getMessage());
            return;
        }
        if (CollectionUtils.isEmpty(liveInfos)) {
            return;
        }
        Integer total = liveInfos.size();
//        List<LiveRoom> liveRoomList = new ArrayList<>();
//        for (WxMaLiveResult.RoomInfo liveInfo : liveInfos) {
//            LiveRoom liveRoom = mapperFacade.map(liveInfo,LiveRoom.class);
//            LiveRoom.RoomToolsVO roomToolsVo = new LiveRoom.RoomToolsVO();
//            // 设置微信直播间功能设置信息
//            roomToolsVo.setCloseKf(liveInfo.getCloseKf());
//            roomToolsVo.setCloseReplay(liveInfo.getCloseReplay());
//            roomToolsVo.setCloseComment(liveInfo.getCloseComment());
//            roomToolsVo.setCloseGoods(liveInfo.getCloseGoods());
//            roomToolsVo.setCloseLike(liveInfo.getCloseLike());
//            liveRoom.setRoomTools(Json.toJsonString(roomToolsVo));
//            liveRoomList.add(liveRoom);
//        }
        // 批量修改
        liveRoomMapper.updateBatchByRoomId(liveInfos);
        int pages = (int) Math.ceil(Arith.div(total, MAX_PAGE_NUM));
        // 4.保存or修改商家次数记录
        if (Objects.isNull(liveLogDb)) {
            LiveLog liveLog = new LiveLog();
            liveLog.setCreateTime(new Date());
            liveLog.setNum(1);
            liveLog.setShopId(Constant.PLATFORM_SHOP_ID);
            liveLog.setType(LiveInterfaceType.ROOM_LIST.value());
            liveLogService.save(liveLog);
        } else {
            liveLogDb.setNum(liveLogDb.getNum() + pages);
            liveLogService.update(liveLogDb);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveLiveRoom(LiveRoom liveRoom) {
        // 1.校验今日可用次数并保存or修改商家次数记录
        liveLogService.checkNumsAndSaveLog(liveRoom.getShopId(), LiveInterfaceType.CREATE_ROOM, "创建直播间");

        // 校验时间,开始时间需要在当前时间的10分钟后 并且开始时间不能在6个月后,
        // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
        Date startTime = liveRoom.getStartTime();
        Date endTime = liveRoom.getEndTime();
        // 1. 开始时间是否在当前时间和十分钟内的时间内，如果为true则表示错误，抛出异常
        // 2. 开始时间是否在当前时间和六个月的时间内，如果为false则表示错误，抛出异常
        boolean expired = DateUtil.isIn(startTime, new Date(), DateUtil.offsetMinute(new Date(), 10)) ||
                !DateUtil.isIn(startTime, new Date(), DateUtil.offsetMonth(new Date(), 6));
        // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
        // 1. 结束时间是否和起始时间间隔不得短于30分钟，如果为true则表示错误，抛出异常
        // 2. 结束时间是否在起始时间开始后的24小时的时间内，如果为false则表示错误，抛出异常
        boolean expiredEndTime = DateUtil.isIn(endTime, startTime, DateUtil.offsetMinute(startTime, 30)) ||
                !DateUtil.isIn(endTime, startTime, DateUtil.offsetHour(startTime, 24));

        if (DateUtil.compare(startTime, endTime) > 0) {
            // 开始时间不能大于结束时间
            throw new LuckException("开始时间不能大于结束时间");
        }
        if (expired) {
            // 开始时间需要在当前时间的10分钟后,并且不能在6个月后
            throw new LuckException("开始时间需要在当前时间的15分钟后,并且不能在6个月后!");
        }
        if (expiredEndTime) {
            // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
            throw new LuckException("开始时间和结束时间间隔不得短于30分钟，不得超过24小时");
        }
        // 校验图片
        this.checkImg(liveRoom);
        // 1.将背景图，封面图，分享图添加到微信临时素材
        // 发起微信审核, 先获取微信的media_id
        String coverMediaId = wxImageUtil.wxImageUpload(liveRoom.getCoverImg());
        String feedsImgMediaId = wxImageUtil.wxImageUpload(liveRoom.getFeedsImg());
        String shareImgMediaId = wxImageUtil.wxImageUpload(liveRoom.getShareImg());
        liveRoom.setCoverImgId(coverMediaId);
        liveRoom.setShareImgId(shareImgMediaId);
        liveRoom.setFeedsImgId(feedsImgMediaId);
        LiveRoom.RoomToolsVO roomToolsVo = liveRoom.getRoomToolsVo();
        // 2.调用微信添加直播间接口添加直播间
        WxMaLiveRoomInfo roomInfo = mapperFacade.map(liveRoom, WxMaLiveRoomInfo.class);
        roomInfo.setStartTime(liveRoom.getStartTime().getTime() / 1000);
        roomInfo.setEndTime(liveRoom.getEndTime().getTime() / 1000);
        roomInfo.setFeedsImg(feedsImgMediaId);
        // 设置微信直播间功能设置信息
        roomInfo.setCloseShare(roomToolsVo.getCloseShare());
        roomInfo.setCloseKf(roomToolsVo.getCloseKf());
        roomInfo.setCloseReplay(roomToolsVo.getCloseReplay());
        roomInfo.setCloseComment(roomToolsVo.getCloseComment());
        roomInfo.setCloseGoods(roomToolsVo.getCloseGoods());
        roomInfo.setCloseLike(roomToolsVo.getCloseLike());
        roomInfo.setCoverImg(liveRoom.getCoverImgId());
        roomInfo.setShareImg(liveRoom.getShareImgId());
        try {
            WxMaCreateRoomResult wxMaCreateRoomResult = wxConfig.getWxMaService().getLiveService().createRoom(roomInfo);
            // 4.保存直播间信息到数据库
            liveRoom.setRoomTools(Json.toJsonString(liveRoom.getRoomToolsVo()));
            liveRoom.setRoomId(wxMaCreateRoomResult.getRoomId());
        } catch (WxErrorException e) {
            if (Objects.equals(e.getError().getErrorCode(), LiveConstant.WECHAT_NAME_LENGTH_ERROR)) {
                // 名称长度不符合规则！
                throw new LuckException("名称长度不符合规则！");
            }
            if (Objects.equals(e.getError().getErrorCode(), LiveConstant.WECHAT_CHECK)) {
                // 主播微信号未实名认证
                throw new LuckException("主播微信号未实名认证");
            }
            if (Objects.equals(e.getError().getErrorCode(), LiveConstant.ROOM_COVER_IMAGE_ERROR)) {
                // 直播间封面图不合规
                throw new LuckException("直播间封面图不合规");
            }
            if (Objects.equals(e.getError().getErrorCode(), LiveConstant.WECHAT_NO_CS_CHECK)) {
                // 未在小程序管理后台配置客服
                throw new LuckException("未在小程序管理后台配置客服");
            }
            if (!Objects.equals(e.getError().getErrorCode(), 0)) {
                // 创建失败，请仔细检查直播间的配置
                throw new LuckException("创建失败，请仔细检查直播间的配置");
            }
        }
        if (Objects.isNull(liveRoom.getRoomId())) {
            // 主播微信号未实名认证
            throw new LuckException("主播微信号未实名认证");
        }
        save(liveRoom);
    }

    @Override
    public PageVO<LiveRoomVO> pageRoomAndDetail(PageDTO pageDTO, LiveRoomDTO liveRoom) {
        return PageUtil.doPage(pageDTO, () -> liveRoomMapper.pageRoomAndDetail(liveRoom));
    }

    /**
     * 核验直播间图片信息
     *
     * @param liveRoom
     */
    private void checkImg(LiveRoom liveRoom) {
        if (Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getCoverImg()), LiveConstant.WEBP) ||
                Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getFeedsImg()), LiveConstant.WEBP) ||
                Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getShareImg()), LiveConstant.WEBP)) {
            throw new LuckException("图片不能使用webp格式,推荐使用jpg或png");
        }
    }
}
